import 旧版作用域相关.*;

public class Cymbol语言监听器 extends CymbolBaseListener {

    public 旧版作用域相关.符号表 符号表;
    private 作用域 当前作用域;
    
    // todo: 需要手工构造抽象语树

    @Override
    public void enterCompilationUnit(CymbolParser.CompilationUnitContext ctx) {
        符号表 = new 符号表();
        当前作用域 = 符号表.全局作用域;
    }

    @Override
    public void enterMethodDeclaration(CymbolParser.MethodDeclarationContext ctx) {
        var 返回值类型 = (类型)当前作用域.解析(ctx.type().getText()); // 把 type 符号转换为一个类型
        当前作用域 = new 方法作用域符号(ctx.ID().getText(), 返回值类型, 当前作用域); // 进入方法作用域
    }

    @Override
    public void exitMethodDeclaration(CymbolParser.MethodDeclarationContext ctx) {
        当前作用域 = 当前作用域.取父作用域(); // 退出方法作用域
    }

    @Override
    public void enterFormalParameters(CymbolParser.FormalParametersContext ctx) {
        for (var i = 0; i < ctx.type().size(); i++) {
            var 参数类型 = (类型)当前作用域.解析(ctx.type(i).getText());
            var 参数名称 = ctx.ID(i).getText();
            var 参数 = new 变量符号(参数名称, 参数类型);
            当前作用域.定义(参数);
        }
    }

    @Override
    public void enterBlock(CymbolParser.BlockContext ctx) {
        当前作用域 = new 局部作用域(当前作用域); // 进入局部作用域
    }

    @Override
    public void exitBlock(CymbolParser.BlockContext ctx) {
        当前作用域 = 当前作用域.取父作用域(); // 退出局部作用域
    }

    @Override
    public void enterVarDeclaration(CymbolParser.VarDeclarationContext ctx) {
        当前作用域.定义(new 变量符号(ctx.ID().getText(), (类型)当前作用域.解析(ctx.type().getText())));
    }

    @Override
    public void enterPrimary(CymbolParser.PrimaryContext ctx) {
        if (ctx.ID() == null) return;
        try {
            当前作用域.解析(ctx.ID().getText());
        } catch (RuntimeException e) {
            throw new RuntimeException("未定义的变量: " + ctx.ID().getText());
        }
    }
}
